import 'dart:convert';

import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get/get_core/get_core.dart';
import 'package:get/get_navigation/get_navigation.dart';
import 'package:vape_xe/routes/app_pages.dart';
import 'package:vape_xe/services/services.dart';
import 'package:vape_xe/utils/utils.dart';

class CustomInterceptor implements InterceptorsWrapper {
  final CancelToken cancelToken;

  CustomInterceptor(this.cancelToken);

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    // 如果你想完成请求并返回一些自定义数据，可以resolve 一个`Response`,如`handler.resolve(response)`。
    // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义response.
    Loading.dismiss();
    ErrorEntity errorEntity = createErrorEntity(err);
    // if (errorEntity.code == 401) UserStore.to.onLogout();
    Loading.showError(errorEntity.message);
  }

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // 如果你想完成请求并返回一些自定义数据，你可以resolve一个Response对象 `handler.resolve(response)`。
    // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义response.
    //
    // 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象,如`handler.reject(error)`，
    // 这样请求将被中止并触发异常，上层catchError会被调用。
    if (UserStore.to.hasToken) {
      options.headers['userId'] = UserStore.to.profile.id;
      options.headers['token'] = UserStore.to.profile.token;
    }
    options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
    options.headers['country'] = getCountry();
    options.headers['language'] = ConfigStore.to.locale.languageCode;

    /// 接口签名
    String timeStamp = (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();
    options.headers['appid'] = dotenv.env['APP_ID'];
    options.headers['timeStamp'] = timeStamp;
    options.headers['sign'] = sign(options, timeStamp);

    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 如果你想终止请求并触发一个错误,你可以 reject 一个`DioError`对象,如`handler.reject(error)`，
    // 这样请求将被中止并触发异常，上层catchError会被调用。
    var dismissDialogAuto = response.requestOptions.extra['dismissDialogAuto'] ?? true;
    if (dismissDialogAuto) Loading.dismiss();
    final initData = json.decode(response.toString());
    if (initData['statusCode'] == '200') {
      handler.next(response);
    } else if (initData['statusCode'] == '403') {
      //token过期
      Loading.showError(initData['message']);
      UserStore.to.onLogout();
      Get.offAllNamed(Routes.SIGN_IN);
    } else {
      Loading.showError(initData['message']);
      handler.reject(DioException(requestOptions: response.requestOptions, message: initData['message']));
    }
  }

  String sign(RequestOptions options, String timeStamp) {
    /// Step 1: 将 appid、appSecret 和 timeStamp 放入集合 M
    Map<String, dynamic> map = {};
    if (options.method == 'GET') {
      map = options.queryParameters;
    } else if (options.method == 'POST') {
      map = options.data;
    }
    map['appid'] = dotenv.env['APP_ID'];
    map['appSecret'] = dotenv.env['APP_SECRET'];
    map['timeStamp'] = timeStamp;

    /// Step 2: 过滤非空参数并排序
    map.removeWhere((key, value) => value == null || value.toString().isEmpty);
    var sortedKeys = map.keys.toList()..sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));

    /// Step 3: 拼接成字符串
    String stringA = sortedKeys.map((key) => '$key=${map[key]}').join('&');
    Get.log('sign string: $stringA');

    /// Step 4: 进行 MD5 签名
    var bytes = utf8.encode(stringA);
    var digest = md5.convert(bytes);
    return digest.toString().toUpperCase();
  }

  String getCountry() {
    switch (ConfigStore.to.countryCode) {
      case '66':
        return 'thailand';
      default:
        return 'malaysia';
    }
  }
}

// 错误信息
ErrorEntity createErrorEntity(DioException error) {
  switch (error.type) {
    case DioExceptionType.cancel:
      return ErrorEntity(code: -1, message: "请求取消");
    case DioExceptionType.connectionError:
      return ErrorEntity(code: -1, message: "连接错误");
    case DioExceptionType.connectionTimeout:
      return ErrorEntity(code: -1, message: "连接超时");
    case DioExceptionType.sendTimeout:
      return ErrorEntity(code: -1, message: "请求超时");
    case DioExceptionType.receiveTimeout:
      return ErrorEntity(code: -1, message: "响应超时");
    case DioExceptionType.badResponse:
      return ErrorEntity(code: -1, message: "服务器错误");
    case DioExceptionType.badCertificate:
      return ErrorEntity(code: -1, message: "证书错误");
    default:
      return ErrorEntity(code: -1, message: "未知错误");
  }
}

class ErrorEntity implements Exception {
  int code = -1;
  String message = "";

  ErrorEntity({required this.code, required this.message});

  @override
  String toString() {
    if (message == "") return "Exception";
    return "Exception: code $code, $message";
  }
}
